﻿using AntDesign;
using AntDesign.TableModels;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Xms.Abp.Application.Dtos;
using Xms.Abp.Authorization;
using Xms.Abp.Data;

namespace Xms.Abp.AntDesignUI;

public partial class PagingListView<TPagingListViewModel, TKey, TPagedParameter, TPermissionConsts> : AbpAntComponentBase
    where TPagingListViewModel : class, IEntityDto<TKey>
    where TPagedParameter : class, IPagedSortedAndFilterParameter, new()
    where TPermissionConsts : class, IPermissionsConst
{
    private readonly TPagedParameter PagedParameter = new();
    protected int CurrentPageIndex = 1;
    protected int CurrentPageSize = 1;
    protected string CurrentSorting;
    protected int TotalCount;
    protected bool PagingLoading = true;
    protected bool AdvanceSearching = true;


    #region Policy
    protected virtual string DetailsPolicyName => GetPolicy();
    protected virtual string CreatePolicyName => GetPolicy();
    protected virtual string UpdatePolicyName => GetPolicy();
    protected virtual string DeletePolicyName => GetPolicy();
    protected virtual string DeleteManyPolicyName => GetPolicy();
    protected virtual string ToggleEnablePolicyName => GetPolicy();
    protected virtual string ExportPolicyName => GetPolicy();
    protected virtual string ImportPolicyName => GetPolicy();

    public bool HasDetailsPermission => HasPermission(DetailsPolicyName);
    public bool HasCreatePermission => HasPermission(CreatePolicyName);
    public bool HasUpdatePermission => HasPermission(UpdatePolicyName);
    public bool HasDeletePermission => HasPermission(DeletePolicyName);
    public bool HasDeleteManyPermission => HasPermission(DeleteManyPolicyName);
    public bool HasToggleEnablePermission => HasPermission(ToggleEnablePolicyName);
    public bool HasExportPermission => HasPermission(ExportPolicyName);
    public bool HasImportPermission => HasPermission(ImportPolicyName);
    public bool HasPermission(string policyName)
    {
        if (policyName == null)
        {
            return true;
        }
        return GrantedPolicyNames.Contains(policyName);
    }
    protected virtual async Task SetPermissionsAsync()
    {
        GrantedPolicyNames.AddRange(await AuthorizationService.FilterGrantedAsync(Policies.Values));
    }

    protected virtual Dictionary<string, string> Policies { get; }
    protected virtual List<string> GrantedPolicyNames { get; }

    protected virtual string GetPolicy([CallerMemberName] string memberName = null)
    {
        memberName = memberName.RemovePostFix("PolicyName").RemovePostFix("Async");
        return Policies.GetOrDefault(memberName);
    }
    protected virtual async Task CheckPolicyAsync([CanBeNull] string policyName)
    {
        if (string.IsNullOrEmpty(policyName))
        {
            return;
        }

        await AuthorizationService.CheckAsync(policyName);
    }

    protected virtual async Task CheckDetailsPolicyAsync()
    {
        await CheckPolicyAsync(DetailsPolicyName);
    }
    protected virtual async Task CheckCreatePolicyAsync()
    {
        await CheckPolicyAsync(CreatePolicyName);
    }
    protected virtual async Task CheckUpdatePolicyAsync()
    {
        await CheckPolicyAsync(UpdatePolicyName);
    }
    protected virtual async Task CheckDeletePolicyAsync()
    {
        await CheckPolicyAsync(DeletePolicyName);
    }
    protected virtual async Task CheckDeleteManyPolicyAsync()
    {
        await CheckPolicyAsync(DeleteManyPolicyName);
    }
    protected virtual async Task CheckToggleEnablePolicyAsync()
    {
        await CheckPolicyAsync(ToggleEnablePolicyName);
    }
    protected virtual async Task CheckExportPolicyAsync()
    {
        await CheckPolicyAsync(ExportPolicyName);
    }
    protected virtual async Task CheckImportPolicyAsync()
    {
        await CheckPolicyAsync(ImportPolicyName);
    }
    #endregion

    [Parameter] public string ModuleName { get; set; }

    [Parameter] public string Title { get; set; }

    [Parameter] public bool Creatable { get; set; }

    [Parameter] public bool Exportable { get; set; }

    [Parameter] public bool DeleteManyable { get; set; }

    [Parameter] public bool Importable { get; set; }

    [Parameter] public IEnumerable<TPagingListViewModel> DataSource { get; set; }

    [Parameter] public RenderFragment<TPagedParameter> AdvanceSearch { get; set; }

    [Parameter] public RenderFragment<TPagingListViewModel> Columns { get; set; }

    [Parameter] public RenderFragment ToolbarMoreActions { get; set; }

    [Parameter] public RenderFragment<TPagingListViewModel> RowMoreActions { get; set; }

    [Parameter] public Func<Task<PagedResult<TPagingListViewModel>>, TPagedParameter> QueryPage { get; set; }

    protected static ConcurrentDictionary<Type, TableColumnInfo[]> TypesColumns = new();

    protected TableColumnInfo[] GetTableColumnInfos()
    {
        return TypesColumns.GetOrAdd(typeof(TPagingListViewModel), XmsUIHelper.GetTableColumnInfos<TPagingListViewModel>());
    }

    protected virtual Func<RowData<TPagingListViewModel>, bool> IsTableRowExpandable()
    {
        return r => r.Data is not IHasChildren<TPagingListViewModel> || r.Data is IHasRemark s && !string.IsNullOrWhiteSpace(s.Remark);
    }

    protected virtual bool IsSelectionDisabled(TPagingListViewModel model)
    {
        return false;
    }

    protected virtual async Task OnRowActionClickAsync(string action, TPagingListViewModel model)
    {
        await Task.CompletedTask;
    }

    protected virtual async Task OnToolbarActionClickAsync(string action)
    {
        await Task.CompletedTask;
    }

    protected virtual async Task OnSearchClickAsync()
    {
        await Task.CompletedTask;
    }

    protected void OnPagingChange(PaginationEventArgs args)
    {

    }

    protected Func<PaginationTotalContext, string> PagingShowTotal()
    {
        return ctx => $"{ctx.Range.from}-{ctx.Range.to} of {ctx.Total} items";
    }
}
